<!--
* @Description: 表格
* @Version: 1.0.0
-->
<template>
  <div class="one-seve-table-box" :style="{ height: _height }" ref="noeSeveTableMain" v-loading="loading">
    <div class="one-seve-table" :style="{ height: _table_height }">
      <el-table ref="tableRef" v-bind="$attrs" :data="processTableData" :border="border" :row-key="rowKey" @selection-change="selectionChange" size="small">
        <slot></slot>
        <template v-for="item in tableColumns" :key="item">
          <el-table-column v-bind="item" :align="item.align ?? 'center'" :reserve-selection="item.type == 'selection'" v-if="item.type && columnTypes.includes(item.type)">
            <template #default="scope">
              <!-- 插槽 扩展 -->
              <template v-if="item.type == 'expand'">
                <slot :name="item.type" v-bind="scope" />
              </template>
              <!-- 插槽 单选 复选 -->
              <el-radio v-if="item.type == 'radio'" v-model="radio" :label="scope.row[rowKey]" size="small">
                <i></i>
              </el-radio>
              <!-- 插槽 拖拽 -->
              <el-tag v-if="item.type == 'sort'" class="move" size="small">
                <el-icon>
                  <DCaret />
                </el-icon>
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column v-bind="item" :align="item.align ?? 'center'" v-if="!item.type && item.prop && !item.isHide">
            <!-- 自定义表格头部内容，slot的格式为 item.prop+Header,例如：#idHeader-->
            <template #header="scope">
              <slot v-if="$slots[item.prop] + 'Header'" :name="item.prop + 'Header'" v-bind="scope" />
            </template>
            <!-- 自定义表格内容，slot的格式为 item.prop,例如：#id-->
            <template #default="scope">
              <slot v-if="$slots[item.prop]" :name="item.prop" v-bind="scope" />
            </template>
          </el-table-column>
        </template>
        <!-- 插入表格最后一行之后的插槽 -->
        <template #append>
          <slot name="append" />
        </template>
        <!-- 无数据 -->
        <template #empty>
          <el-empty :description="emptyText" :image-size="100"></el-empty>
        </template>
      </el-table>
    </div>
    <!-- 分页组件 -->
    <slot name="pagination">
      <div v-if="pagination">
        <el-pagination background layout="total, sizes, prev, pager, next, jumper" :current-page="pageable.page" :page-size="pageable.pageSize" :total="pageable.total" :page-sizes="pageSizes" @current-change="handleCurrentChange" @size-change="handleSizeChange" size="small"></el-pagination>
      </div>
    </slot>
  </div>
</template>

<script setup>
import { useTable, useSelection } from "./hooks";
import Sortable from "sortablejs";

const props = defineProps({
  // 列配置项
  columns: {
    type: Array,
    required: true,
  },
  // 静态 table data 数据，若存在则不会使用 requestApi 返回的 data
  data: {
    type: Array,
  },
  // 请求表格数据的 api
  requestApi: {
    type: Function,
  },
  // 初始化请求参数
  initParam: {
    type: Object,
    default: () => {},
  },
  // 表格 api 请求错误监听
  requestError: {
    type: Function,
  },
  // 返回数据的回调函数，可以对数据进行处理
  dataCallback: {
    type: Function,
  },
  // 是否需要分页组件
  pagination: {
    type: Boolean,
    default: true,
  },
  // 每页显示个数选择器的选项设置
  pageSizes: {
    type: Array,
    default: () => [10, 20, 50, 100],
  },
  // 是否带有纵向边框
  border: {
    type: Boolean,
    default: false,
  },
  // 空数据展示提示文字
  emptyText: {
    type: String,
    default: "暂无数据",
  },
  rowKey: {
    type: String,
    default: "id",
  },
});

// table 实例
const tableRef = ref();
// 表格操作 Hooks   searchInitParam,
const { tableData, pageable, loading, searchParam, getTableList, search, reset, handleSizeChange, handleCurrentChange } = useTable(props.requestApi, props.initParam, props.pagination, props.dataCallback, props.requestError);
// 表格多选 Hooks
const { selectionChange, selectedList, selectedListKeys, isSelected } = useSelection(props.rowKey);
// 单选值
const radio = ref("");
// 接收 columns 并设置为响应式
const tableColumns = reactive(props.columns);
// column 列类型
/**
 * @description: 列类型
 *                  selection: 多选
 *                  radio: 单选
 *                  index: 序号
 *                  expand: 展开
 *                  sort: 排序
 */
const columnTypes = ["selection", "radio", "index", "expand", "sort"];

// 监听页面 initParam 改化，重新获取表格数据
watch(() => props.initParam, getTableList, { deep: true });

// 定义 emit 事件
const emit = defineEmits();

onMounted(() => {
  dragSort();
  if (props.requestApi) {
    getTableList();
  }
});

/**
 * @description: 拖拽排序
 */
const dragSort = () => {
  const tbody = document.querySelector(".el-table__body-wrapper tbody");
  Sortable.create(tbody, {
    handle: ".move",
    animation: 300,
    onEnd({ newIndex, oldIndex }) {
      const [removedItem] = processTableData.value.splice(oldIndex, 1);
      processTableData.value.splice(newIndex, 0, removedItem);
      emit("dargSort", { newIndex, oldIndex });
    },
  });
};

/**
 * @description 处理表格数据
 */
const processTableData = computed(() => {
  if (!props.data) return tableData.value;
  if (!props.pagination) return props.data;
  return props.data.slice((pageable.value.page - 1) * pageable.value.pageSize, pageable.value.pageSize * pageable.value.page);
});

/**
 * @description 表格高度
 */
const _height = computed(() => {
  return props.height ? props.height + "px" : "100%";
});

/**
 * @description: 默认echarts样式
 */
const _table_height = computed(() => {
  return !props.pagination ? "100%" : "calc(100% - 50px)";
});

// 暴露给父组件的参数和方法 (外部需要什么，都可以从这里暴露出去)
defineExpose({
  element: tableRef,
  tableData: processTableData, //表格数据
  radio, //表格单选的数据
  pageable, //分页信息，包含：page:当前页数; pageSize:每页展示数量; total:总共条数;
  getTableList, //获取表格数据请求方法，只有传入requestApi时才有用
  isSelected, //是否选择数据，type=selection时有用
  selectedList, //选择数据列表数组，type=selection时有用
  selectedListKeys, //选择数据列表的ID数组，type=selection时有用
  search,
  searchParam,
  reset,
});
</script>

<style scoped lang="scss">
.one-seve-table-box,
.one-seve-table {
  display: flex;
  flex: 1;
  flex-direction: column;
  width: 100%;
  height: 100%;

  // el-table 表格样式
  .el-table {
    flex: 1;

    table {
      width: 100%;
    }

    .el-table__header th {
      height: 45px;
      font-size: 15px;
      font-weight: bold;
      color: var(--el-text-color-primary);
      background: var(--el-fill-color-light);
    }

    .el-table__row {
      height: 45px;
      font-size: 14px;

      .move {
        cursor: move;

        .el-icon {
          cursor: move;
        }
      }
    }

    // 设置 el-table 中 header 文字不换行，并省略
    .el-table__header .el-table__cell > .cell {
      // white-space: nowrap;
      white-space: wrap;
    }

    // 解决表格数据为空时样式不居中问题(仅在element-plus中)
    .el-table__empty-block {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);

      .table-empty {
        line-height: 30px;
      }
    }

    // table 中 image 图片样式
    .table-image {
      width: 50px;
      height: 50px;
      border-radius: 50%;
    }
  }

  // 表格 pagination 样式
  .el-pagination {
    display: flex;
    justify-content: flex-end;
    margin: 12px 20px;
  }
}

/* el-table 组件大小 */
.el-table--small {
  .el-table__header th {
    height: 40px !important;
    font-size: 14px !important;
  }

  .el-table__row {
    height: 40px !important;
    font-size: 13px !important;
  }
}

.el-table--large {
  .el-table__header th {
    height: 50px !important;
    font-size: 16px !important;
  }

  .el-table__row {
    height: 50px !important;
    font-size: 15px !important;
  }
}
</style>
